package view;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;

import mt.Estado;
import mt.Fprograma;
import mt.MT;
import arq.OperacoesArquivo;

import java.awt.Toolkit;

public class Janela extends JFrame
{
	private static final long serialVersionUID = 1L;
	private JPanel contentPane;
	private JTextField word_text;
	private JTable table;
	JSpinner spinner;
	ControlaTabela modelo_fp = new ControlaTabela();
	ControlaTabela modelo_fita = new ControlaTabela();
	private JTable table_1;
	Estado[] estados;
	private JTextField final_state;
	private JTextField initial_state;
	private JFileChooser jFChosen;
	private String diretorio = "";
	private String est_term[];
	private boolean construiu = false;
	private boolean autoscroll = true;
	MT maq;
	JScrollPane scrollPane_1;
	ArrayList <Integer> listIndice = new ArrayList<Integer>();
	JMenuItem mntmNewMenuItem;
	JMenuItem mntmCdc;

	public Janela() throws IOException
	{
		setIconImage(Toolkit.getDefaultToolkit().getImage("ico.jpg"));
		setResizable(false);
		setTitle("Turing Machine Simulator");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 600, 396);
		setLocationRelativeTo(null);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(null);

		JMenuBar menuBar = new JMenuBar();
		menuBar.setBounds(0, 0, 594, 21);
		contentPane.add(menuBar);

		JMenu mnFile = new JMenu("File");
		menuBar.add(mnFile);

		JMenuItem mntmNew = new JMenuItem("New");
		mntmNew.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				word_text.setText("");
				final_state.setText("");
				initial_state.setText("");
				spinner.setValue(1);
				modelo_fp.limpaTabela();
				modelo_fp.adicionaLinha();
				modelo_fita.limpaTabela();
				setTitle("Turing Machine Simulator");

			}
		});
		mnFile.add(mntmNew);

		JSeparator separator_2 = new JSeparator();
		mnFile.add(separator_2);

		JMenuItem mntmOpen = new JMenuItem("Open");
		mntmOpen.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				Abrir();
			}
		});
		mnFile.add(mntmOpen);

		JSeparator separator = new JSeparator();
		mnFile.add(separator);

		JMenuItem mntmSave = new JMenuItem("Save");
		mntmSave.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				Salvar();
			}
		});
		mnFile.add(mntmSave);

		JMenuItem mntmSaveAs = new JMenuItem("Save as");
		mntmSaveAs.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				Salvar_Como();
			}
		});
		mnFile.add(mntmSaveAs);

		JSeparator separator_1 = new JSeparator();
		mnFile.add(separator_1);

		JMenuItem mntmExit = new JMenuItem("Exit");
		mntmExit.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				if (gravarMudancas())
				{
					System.exit(0);
				}
			}
		});
		mnFile.add(mntmExit);
		
		JMenu mnSetings = new JMenu("Settings");
		menuBar.add(mnSetings);
		
		mntmNewMenuItem = new JMenuItem("");
		mntmNewMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				ArrayList<String> a = new ArrayList<String>();
				try
				{
					a = OperacoesArquivo.Leitura("run.dat");
				} catch (Exception e1)
				{
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				
				if(a.get(a.size() - 1).equals("false"))
				{
					mntmNewMenuItem.setText("Do not show splash screen.");
					a.clear();
					a.add("true");
					try
					{
						OperacoesArquivo.Escrita("run.dat", a);
					} catch (IOException e)
					{
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				}
				else
				{
					mntmNewMenuItem.setText("Show splash screen.");
					a.clear();
					a.add("false");
					try
					{
						OperacoesArquivo.Escrita("run.dat", a);
					} catch (IOException e)
					{
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		});
		
		ArrayList<String> a = new ArrayList<String>();
		try
		{
			a = OperacoesArquivo.Leitura("run.dat");
		} catch (Exception e1)
		{
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		if(a.get(a.size() - 1).equals("false"))
		{
			mntmNewMenuItem.setText("Show splash screen.");
		}
		else
		{
			mntmNewMenuItem.setText("Do not show splash screen.");
		}
		
		mnSetings.add(mntmNewMenuItem);
		
		mntmCdc = new JMenuItem("Scroll manually.");
		mntmCdc.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				
				if(autoscroll)
				{
					autoscroll = false;
					mntmCdc.setText("Scroll automatically.");
				}
				else
				{
					autoscroll = true;
					mntmCdc.setText("Scroll manually.");
				}
			}
		});
		mnSetings.add(mntmCdc);

		JMenu mnHelp = new JMenu("Help");
		menuBar.add(mnHelp);

		JMenuItem mntmAbout = new JMenuItem("About");
		mntmAbout.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				try
				{
					About dialog = new About();
					dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
					dialog.setModal(true);
					dialog.setLocationRelativeTo(null);
					dialog.setVisible(true);
				} catch (Exception e)
				{
					e.printStackTrace();
				}
			}
		});
		mnHelp.add(mntmAbout);

		JLabel lblCadeia = new JLabel("Word");
		lblCadeia.setBounds(10, 32, 46, 14);
		contentPane.add(lblCadeia);

		word_text = new JTextField();
		word_text.setBounds(10, 47, 368, 20);
		contentPane.add(word_text);
		word_text.setColumns(10);

		JButton btnProcess = new JButton("Process");
		btnProcess.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				modelo_fita.model.setColumnCount(0);
				modelo_fita.model.setNumRows(0);

				String[] fita = word_text.getText().split("");
				modelo_fita.adicionaLinha();

				for (int i = 1; i < fita.length; i++)
				{
					modelo_fita.adicionaColuna(null);
					table_1.setDefaultRenderer(Object.class, new CellRenderer());
					table_1.setValueAt(fita[i], 0, i - 1);
				}

				if (!modelo_fp.validaFprog(table))
				{
					JOptionPane.showMessageDialog(null, "The table is not complete.",
							"ERROR", JOptionPane.INFORMATION_MESSAGE);
				} else
				{
					estados = new Estado[table.getRowCount()];
					String aux;
					String[] progs;
					for (int i = 0; i < table.getRowCount(); i++)
					{
						estados[i] = new Estado();
						estados[i].nome = table.getValueAt(i, 0).toString();

						aux = table.getValueAt(i, 1).toString()
								.replaceAll(",", " ").replaceAll("\\(", " ")
								.replaceAll("\\)", " ").replaceAll("\\s+", " ");

						progs = aux.split("; ");

						for (int j = 0; j < progs.length; j++)
						{
							estados[i].fprog
									.add((estados[i].nome + " " + progs[j])
											.replaceAll("\\s+", " "));
						}
					}
					est_term = final_state.getText().split("; ");
					mt.MT.setTerminal(est_term, estados);
					MT maq = new MT(estados, word_text.getText(), initial_state
							.getText());

					while ((maq.fita.indice < maq.fita.tamanho)
							&& (!excecao.ExcecaoIndefinicao.getIndefinicao()))
					{
						maq.novo = Fprograma.fPrograma(maq.atual, maq.estados,
								maq.fita);
						maq.atual = maq.novo;
						for (int i = 0; i < maq.fita.fita.length; i++)
						{
							table_1.setValueAt(maq.fita.fita[i], 0, i);
						}
					}
					
					if(maq.fita.indice < table_1.getColumnCount())
					{	
						table_1.setColumnSelectionInterval(maq.fita.indice,
								maq.fita.indice);
						table_1.setRowSelectionInterval(0, 0);
					}
					else if(maq.fita.indice == table_1.getColumnCount())
					{
						table_1.setColumnSelectionInterval(maq.fita.indice - 1,
								maq.fita.indice - 1);
						table_1.setRowSelectionInterval(0, 0);
					}
					table.setRowSelectionInterval(mt.Fprograma.ind_estado,
							mt.Fprograma.ind_estado);
					if(maq.ehTerminal(maq.atual))
					{
						Toolkit.getDefaultToolkit().beep();
						JOptionPane.showMessageDialog(null, "Accepted word!",
								"Turing Machine Simulator", JOptionPane.INFORMATION_MESSAGE);
					}
					else
					{
						Toolkit.getDefaultToolkit().beep();
						JOptionPane.showMessageDialog(null, "Word does not accept!",
								"Turing Machine Simulator", JOptionPane.INFORMATION_MESSAGE);
					}
					excecao.ExcecaoIndefinicao.setIndefinicao(false);
				}

			}
		});
		btnProcess.setBounds(384, 46, 90, 23);
		contentPane.add(btnProcess);

		final JButton btnStep = new JButton("Step");
		btnStep.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{

				if (!construiu)
				{

					modelo_fita.model.setColumnCount(0);
					modelo_fita.model.setNumRows(0);

					String[] fita = word_text.getText().split("");
					modelo_fita.adicionaLinha();

					for (int i = 1; i < fita.length; i++)
					{
						modelo_fita.adicionaColuna(null);
						table_1.setDefaultRenderer(Object.class,
								new CellRenderer());
						table_1.setValueAt(fita[i], 0, i - 1);
					}

					if (!modelo_fp.validaFprog(table))
					{
						JOptionPane.showMessageDialog(null, "The table is not complete.",
								"ERROR", JOptionPane.INFORMATION_MESSAGE);
					} else
					{
						estados = new Estado[table.getRowCount()];
						String aux;
						String[] progs;
						for (int i = 0; i < table.getRowCount(); i++)
						{
							estados[i] = new Estado();
							estados[i].nome = table.getValueAt(i, 0).toString();

							aux = table.getValueAt(i, 1).toString()
									.replaceAll(",", " ")
									.replaceAll("\\(", " ")
									.replaceAll("\\)", " ")
									.replaceAll("\\s+", " ");

							progs = aux.split("; ");

							for (int j = 0; j < progs.length; j++)
							{
								estados[i].fprog
										.add((estados[i].nome + " " + progs[j])
												.replaceAll("\\s+", " "));
							}

						}
						est_term = final_state.getText().split("; ");
						mt.MT.setTerminal(est_term, estados);
						maq = new MT(estados, word_text.getText(),
								initial_state.getText());
						if (word_text.getText().equals(""))
						{
							excecao.ExcecaoIndefinicao.Erro();
						} else
						{
							table.setRowSelectionInterval(0, 0);
							table_1.setColumnSelectionInterval(0, 0);
							table_1.setRowSelectionInterval(0, 0);
						}
						word_text.setEditable(false);
						construiu = true;
					}
				} else
				{	
					
					listIndice.add(maq.fita.indice);
					
					if((maq.fita.indice > 3) && (maq.fita.indice < (maq.fita.tamanho - 1) && (autoscroll)))
					{
						if(listIndice.get(listIndice.size() - 1) > listIndice.get(listIndice.size() - 2))
							scrollPane_1.getViewport().setViewPosition(new Point(75 + scrollPane_1.getViewport().getViewPosition().x, 0));
						else
							scrollPane_1.getViewport().setViewPosition(new Point(-75 + scrollPane_1.getViewport().getViewPosition().x, 0));
					}
					
					if ((maq.fita.indice < maq.fita.tamanho)
							&& (!excecao.ExcecaoIndefinicao.getIndefinicao()))
					{
						maq.novo = Fprograma.fPrograma(maq.atual, maq.estados,
								maq.fita);
						maq.atual = maq.novo;
						for (int i = 0; i < maq.fita.fita.length; i++)
						{
							table_1.setValueAt(maq.fita.fita[i], 0, i);
						}
						table.setRowSelectionInterval(mt.Fprograma.ind_estado,
								mt.Fprograma.ind_estado);
						if (maq.fita.indice < table_1.getColumnCount())
							table_1.setColumnSelectionInterval(maq.fita.indice,
									maq.fita.indice);
						table_1.setRowSelectionInterval(0, 0);
					} else
					{

						if(maq.ehTerminal(maq.atual))
						{
							Toolkit.getDefaultToolkit().beep();
							JOptionPane.showMessageDialog(null, "Accepted word!",
									"Turing Machine Simulator", JOptionPane.INFORMATION_MESSAGE);
						}
						else
						{
							Toolkit.getDefaultToolkit().beep();
							JOptionPane.showMessageDialog(null, "Word does not accept!",
									"Turing Machine Simulator", JOptionPane.INFORMATION_MESSAGE);
						}
						excecao.ExcecaoIndefinicao.setIndefinicao(false);
						word_text.setEditable(true);
						construiu = false;
					}
				}

			}
		});
		btnStep.setBounds(484, 46, 90, 23);
		contentPane.add(btnStep);

		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(10, 118, 564, 150);
		contentPane.add(scrollPane);

		table = new JTable();
		table.addKeyListener(new KeyAdapter()
		{

		});
		modelo_fp.adicionaColuna("State");
		modelo_fp.adicionaColuna("Program Function");
		modelo_fp.adicionaLinha();
		table.setModel(modelo_fp.model);
		table.getColumnModel().getColumn(1).setPreferredWidth(400);

		scrollPane.setViewportView(table);

		spinner = new JSpinner();
		spinner.addChangeListener(new ChangeListener()
		{
			public void stateChanged(ChangeEvent arg0)
			{
				modelo_fp.mudaLinha(
						Integer.parseInt(spinner.getValue().toString()), table);
			}
		});
		spinner.setModel(new SpinnerNumberModel(new Integer(1), new Integer(1),
				null, new Integer(1)));
		spinner.addKeyListener(new KeyAdapter()
		{

		});
		spinner.addMouseListener(new MouseAdapter()
		{
		});
		spinner.setBounds(53, 95, 37, 20);
		contentPane.add(spinner);

		JLabel lblAddState = new JLabel("States");
		lblAddState.setBounds(10, 98, 46, 14);
		contentPane.add(lblAddState);

		scrollPane_1 = new JScrollPane();
		scrollPane_1.setBounds(10, 310, 564, 35);
		contentPane.add(scrollPane_1);

		table_1 = new JTable()
		{
			private static final long serialVersionUID = 1L;

			public boolean isCellEditable(int row, int column)
			{
				return false;
			}
		};
		table_1.setCellSelectionEnabled(true);

		table_1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		table_1.setTableHeader(null);
		table_1.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

		table_1.setModel(modelo_fita.model);
		scrollPane_1.setViewportView(table_1);

		JLabel lblWordSplit = new JLabel("Word Split");
		lblWordSplit.setBounds(10, 294, 69, 14);
		contentPane.add(lblWordSplit);

		JLabel lblFinalState = new JLabel("Final State");
		lblFinalState.setBounds(296, 98, 60, 14);
		contentPane.add(lblFinalState);

		final_state = new JTextField();
		final_state.setBounds(366, 95, 69, 20);
		contentPane.add(final_state);
		final_state.setColumns(10);

		JLabel lblInitialState = new JLabel("Initial State");
		lblInitialState.setBounds(125, 98, 69, 14);
		contentPane.add(lblInitialState);

		initial_state = new JTextField();
		initial_state.setColumns(10);
		initial_state.setBounds(204, 95, 69, 20);
		contentPane.add(initial_state);
		jFChosen = new JFileChooser();
		jFChosen.setFileFilter(new FileFilter()
		{

			@Override
			public String getDescription()
			{
				return "Turing Machine (*.tms)";
			}

			@Override
			public boolean accept(File arg0)
			{
				return arg0.getName().toLowerCase().endsWith(".tms")
						|| arg0.isDirectory();
			}
		});
	}

	private void Abrir()
	{
		int retorno;

		jFChosen.setDialogTitle("Open file");
		retorno = jFChosen.showOpenDialog(null);

		if (retorno == JFileChooser.APPROVE_OPTION)
		{
			Abre_Arquivo(jFChosen.getSelectedFile().getAbsolutePath());

			this.diretorio = jFChosen.getSelectedFile().getAbsolutePath();
			setTitle("Turing Machine Simulator - " + jFChosen.getSelectedFile().getName());
		}
	}

	private void Abre_Arquivo(String caminho)
	{
		ArrayList<String> CodMT;
		try
		{
			CodMT = arq.OperacoesArquivo.Leitura(caminho);

			estados = new Estado[Integer.parseInt(CodMT.get(0))];
			spinner.setValue(Integer.parseInt(CodMT.get(0)));
			modelo_fp.limpaTabela();
			for (int k = 0; k < Integer.parseInt(CodMT.get(0)); k++)
			{
				estados[k] = new Estado();
				modelo_fp.adicionaLinha();
			}

			initial_state.setText(CodMT.get(1).toString());

			int indice = 0;
			int n_fp = 0;
			for (int i = 1; i < CodMT.size(); i++)
			{

				estados[indice].nome = CodMT.get(i);
				table.setValueAt(CodMT.get(i), indice, 0);

				i++;
				n_fp = Integer.parseInt(CodMT.get(i));

				for (int temp = 0; temp < n_fp; temp++)
				{
					i++;
					estados[indice].fprog.add(CodMT.get(i));
					table.setValueAt(
							(table.getValueAt(indice, 1) + CodMT.get(i))
									.replaceAll("null", "") + "; ", indice, 1);
				}
				i++;
				if (CodMT.get(i).equals("true"))
				{
					estados[indice].terminal = true;
					final_state.setText(estados[indice].nome);

				} else
					estados[indice].terminal = false;

				indice++;
			}
		} catch (IOException e)
		{
			JOptionPane.showMessageDialog(null, "Error opening file!",
					"ERROR", JOptionPane.YES_OPTION);
			Abrir();
		}

	}

	private void Salvar()
	{

		if (diretorio.equals(""))
			Salvar_Como();
		else
			Salvar_Arquivo(this.diretorio);
	}

	private void Salvar_Como()
	{
		int aux;

		jFChosen.setDialogTitle("Save file");
		aux = jFChosen.showSaveDialog(null);
		if (aux == JFileChooser.APPROVE_OPTION)
		{
			this.diretorio = jFChosen.getSelectedFile().getAbsolutePath();
			Salvar_Arquivo(this.diretorio + ".tms");
			setTitle("Turing Machine Simulator - " + jFChosen.getSelectedFile().getName() + ".tms");
		}
	}

	private void Salvar_Arquivo(String caminho)
	{
		if(!modelo_fp.validaFprog(table))
		{
			JOptionPane.showMessageDialog(null, "Error saving the file!",
					"Saved", JOptionPane.INFORMATION_MESSAGE);
			return;
		}
		ArrayList<String> codmt = new ArrayList<String>();

		codmt.add(Integer.toString(table.getRowCount()));

		String fps[];
		String nome_fin;
		for (int i = 0; i < table.getRowCount(); i++)
		{
			
			codmt.add(table.getValueAt(i, 0).toString());
			nome_fin = table.getValueAt(i, 0).toString();

			fps = table.getValueAt(i, 1).toString().split("; ");
			codmt.add(Integer.toString(fps.length));

			for (int j = 0; j < fps.length; j++)
			{
				codmt.add(fps[j]);
			}

			String temp[];
			temp = final_state.getText().split("; ");
			boolean achou = false;
			for (int k = 0; k < est_term.length; k++)
			{
				if (nome_fin.equals(temp[k].replaceAll("\\s+", "")))
				{
					achou = true;
					break;
				}
			}
			if (achou)
			{
				codmt.add("true");
			} else
			{
				codmt.add("false");
			}
		}
		try
		{
			OperacoesArquivo.Escrita(caminho, codmt);
			JOptionPane.showMessageDialog(null, "File saved successfully!",
					"Saved", JOptionPane.INFORMATION_MESSAGE);
		} catch (IOException e)
		{
			JOptionPane.showMessageDialog(null, "Error saving the file!",
					"ERROR", JOptionPane.YES_OPTION);
			Salvar_Como();
		}
	}

	private boolean gravarMudancas()
	{
		int msgBox = JOptionPane.showConfirmDialog(null,
				"You want to save changes?", "Exit",
				JOptionPane.YES_NO_CANCEL_OPTION);

		if (msgBox == JOptionPane.YES_OPTION)
		{
			Salvar();
			return true;
		} else if (msgBox == JOptionPane.CANCEL_OPTION)
		{
			return false;
		}
		return true;
	}
}
